package com.richfun.boot.common.util;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URLEncoder;
import java.util.Arrays;
import java.util.Date;
import java.util.HashSet;
import java.util.Set;

import javax.servlet.http.HttpServletResponse;

import com.richfun.boot.common.exception.SysException;
import org.apache.commons.io.IOUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartFile;

/**
 * 文件上传工具(指定配置文件目录上传)
 * @author geYang
 * @date 2018-06-13
 */
@Component
public class UploadUtil {
    /**
     * 文件指定访问URL
     */
    public static final String BASE_URL = "/niuerlaw_files/";
    /**
     * 文件指定存放目录
     */
    @Value("${upload.base.path}")
    public String basePath;
    /**
     * 用户图片存放目录
     */
    public final String USER_IMAGE = "userimage/";
    /**
     * 图片存放目录
     * */
    public final String IMAGE = "image/";
	/**
     * 其他文件存放目录
     */
    public static final String OTHERF = "outher/";
    /**
     * 允许上传文件集合
     */
    protected static String[] ALLOW_FORMAT = {
            ".jpg", ".png", ".gif", ".jpeg", ".txt", ".zip",
            ".doc", ".docx", ".xls", ".xlsx"
        };
    
    /**
     * 文件上传路径(F:\IMAGE\path)
     * @param path 默认为 OTHER(other)
     * @author geYang
     * @date 2018-06-13 07:06
     * */
    public String getUploadFilePath(String path) {
    	System.out.println("uploadBasePath(配置路径): " + basePath);
        path = CommonUtil.isBlank(path) || path.equals(BASE_URL) || path.equals(basePath) ? OTHERF : path;
        File uploadFile = new File(basePath, path);
        if (!uploadFile.exists()) {
            uploadFile.mkdirs();
        }
        String uploadFilePath = uploadFile.getAbsolutePath();
        System.out.println("uploadFilePath(文件上传路径): " + uploadFilePath);
        return uploadFilePath;
    }
    
    
    /**
     * 文件上传
     * @param file 文件
     * @param path 存放目录
     * @author geYang 2018-06-13 07:09
     * */
    public String upload(MultipartFile file, String path) {
        if (file.isEmpty()) {
            return null;
        }
        String fileName = getFileName(file.getOriginalFilename());
        String fileUrl = null;
        try {
            // 文件存放目录
            String uploadFilePath = getUploadFilePath(path);
            uploadFile(file.getBytes(), uploadFilePath, fileName);
            fileUrl = getFileUrl(path, fileName);
        } catch (IOException e) {
            e.printStackTrace();
        }
        return fileUrl;
    }

    /**
     * 获取文件访问路径
     * */
    public String getFileUrl(String path, String fileName) {
        String fileUrl = BASE_URL + path + fileName;
        System.out.println("fileUrl(文件访问路径): " + fileUrl);
        return fileUrl;
    }
    
    /**
     * 获取文件存放全路径路径(相对路径)
     * @param fileUrl 文件访问路径
     * @return  F:/IMAGE/outher/08.jpg
     * @author geYang 2018-06-13 07:25
     * */
    public String getUploadPath(String fileUrl) {
        String uploadPath = fileUrl.replace(BASE_URL, basePath);
        System.out.println("uploadPath(文件存放路径): " + uploadPath);
        return uploadPath;
    }
    
    /**
     * 生成随机文件名
     * @param originalName 上传文件名
     * @return fileName 随机文件名
     * @author geYang  2018-06-13 10:54
     */
    private String getFileName(String originalName) {
        String suffix = getSuffix(originalName);
        return DateUtil.format(new Date(), "yyyyMMddHHmmss") + StrUtil.randomString(5).toLowerCase() + suffix;
    }

    /**
     * 获取文件后缀名
     */
    public static String getSuffix(String name) {
        String suffix = name.substring(name.lastIndexOf("."));
        if (!checkSuffix(suffix)) {
            throw new SysException("文件不合法");
        }
        return suffix;
    }
    
    /**
     * 判断文件名是否合格
     * @param name
     * @return
     * @author geYang
     * @date 2018-06-13 08:35
     * */
    public static boolean checkName(String name) {
        return checkSuffix(getSuffix(name));
    }

    /**
     * 校验后缀名是否合法
     * */
    private static boolean checkSuffix(String suffix) {
        Set<String> setSuffix = new HashSet<>(Arrays.asList(ALLOW_FORMAT));
        return setSuffix.contains(suffix);
    }
    
    /**
     * 文件上传
     * */
    public static void uploadFile(byte[] file, String filePath, String fileName) throws IOException {
        File targetFile = new File(filePath);
        if (!targetFile.exists()) {
            boolean mkdirs = targetFile.mkdirs();
        }
        FileOutputStream out = new FileOutputStream(filePath + "/" + fileName);
        out.write(file);
        out.flush();
        out.close();
    }
    
    
    /**
     * 获取文件下载数据
     * @author geYang 2018-06-13 10:20
     * */
    private byte[] getDownloadByte(String fileUrl) {
        try {
            String uploadPath = getUploadPath(fileUrl);
            InputStream inputStream = new FileInputStream(new File(uploadPath));
            byte[] data = new byte[inputStream.available()];
            inputStream.read(data);
            inputStream.close();
            return data;
        } catch (IOException e) {
            e.printStackTrace();
            throw new SysException("文件下载异常");
        }
    }

    /**
     * 文件下载
     * @param fileUrl 文件访问路径
     * @param fileName 定义下载文件名,不带后缀
     * @param response
     * @throws IOException
     * @author geYang
     * @date 2018-06-13 10:30
     * */
    public void download(String fileUrl, String fileName ,HttpServletResponse response) throws IOException {
        // 文件下载
        byte[] downloadByte = getDownloadByte(fileUrl);
        if (downloadByte == null) {
            throw new SysException("下载文件不存在");
        }
        int downloadByteLength = downloadByte.length;
        response.reset();
        fileName = URLEncoder.encode(fileName.trim()+getSuffix(fileUrl), "UTF-8");
        response.setHeader("Content-Disposition", "attachment; filename=\""+ fileName  +"\"");  
        response.addHeader("Content-Length", String.valueOf(downloadByteLength));
        response.setContentType("application/octet-stream; charset=UTF-8");
        IOUtils.write(downloadByte, response.getOutputStream());
    }
    
    
}
